/*
 * Colas.c
 *
 *  Created on: 28/09/2011
 *      Author: utn_so
 */
#include "../../headers/GlobalHeader.h"
extern t_log *logger;
extern config configuracion;
extern int32_t cantidadClientesPFS;
extern NodoPFS *listaPFS;


void crear_cola_pedidos(struct t_nodoCola *frente, struct t_nodoCola *fin){
	frente = NULL;
	fin = NULL;
}

void mostrar_cola(struct t_nodoCola *frente){
	struct t_nodoCola *puntero1;
	puntero1 = frente;
	while(puntero1 != NULL){
		 printf("Direccion sector: %i - Lectura o Escritura: %i - Id plan: %s \n",puntero1->pedido.direccionSector,puntero1->pedido.conexion_pfs_id,puntero1->pedido.planificador_id);
		 puntero1 = (*puntero1).siguiente;
	}
}


t_nodoCola **buscar_cola_planificador(t_nodoColaGrande *frente_grande, char planificador[25]){
	t_nodoColaGrande *puntero1 = frente_grande;
	t_nodoCola *puntero_cola;
	int32_t comparacion_string;

	comparacion_string = strcmp(puntero1->planificador_id, planificador);
	while((puntero1 != NULL) && (comparacion_string != 0)){
		puntero1 = (*puntero1).siguienteGrande;
		if(puntero1 != NULL) comparacion_string = strcmp(puntero1->planificador_id, planificador);
	}
	if(puntero1 == NULL) printf("El planificador a eliminar no es válido");
	return &puntero1->siguiente;
/*
	puntero_cola = puntero1->siguiente;
	puntero_cola_anterior = puntero1->siguiente;

	while(puntero_cola != NULL){
		puntero_cola_anterior = puntero_cola;
		puntero_cola = puntero_cola->siguiente;
	}

	return puntero_cola_anterior;
*/
}

bool suprimir_pedido_especifico_de_cola(t_nodoColaGrande **frente, struct t_pedido pedido){
	int32_t comparacion_string;
	t_nodoCola *puntero1 = NULL,* puntero2 = NULL;
	t_nodoColaGrande *aux = *frente;
	bool encontrado_y_removido;
/*
	aux = *frenteGrande;
	comparacion_string = strcmp(aux->planificador_id, pedido.planificador_id);
	  while((aux != NULL) && (comparacion_string != 0)){
		  aux = aux->siguienteGrande;
		  if(aux != NULL) comparacion_string = strcmp(aux->planificador_id, pedido.planificador_id);
	}
*/
//	frente = buscar_cola_planificador(*frenteGrande,pedido.planificador_id);

	//frente= aux->siguiente;

	puntero1 = aux->siguiente;
	//puntero2 = *frente;


	comparacion_string = strcmp((*puntero1).pedido.planificador_id, pedido.planificador_id);
	//comparacion_string2 = strcmp((*puntero1).pedido.lectura_o_escritura, pedido.lectura_o_escritura);
	while((puntero1 != NULL) && (((*puntero1).pedido.direccionSector != pedido.direccionSector) || ((*puntero1).pedido.conexion_ppd_id != pedido.conexion_ppd_id) || ((*puntero1).pedido.conexion_pfs_id != pedido.conexion_pfs_id) || ((*puntero1).pedido.lectura_o_escritura != pedido.lectura_o_escritura) || (comparacion_string != 0))){
		puntero2 = puntero1;
		puntero1 = (*puntero1).siguiente;
		if(puntero1 != NULL) {
			comparacion_string = strcmp((*puntero1).pedido.planificador_id, pedido.planificador_id);
			//comparacion_string2 = strcmp((*puntero1).pedido.lectura_o_escritura, pedido.lectura_o_escritura);
		}
	}

	if(puntero1 == aux->siguiente){
		(*frente)->siguiente = (*puntero1).siguiente;
		encontrado_y_removido = true;
		if((*frente)->ultimo == puntero1) (*frente)->ultimo = (*puntero1).siguiente;
	}

	else{
		if(puntero1 == NULL){
			encontrado_y_removido = false;
			return encontrado_y_removido;
		}
		else{
		(*puntero2).siguiente = (*puntero1).siguiente;
		if((*frente)->ultimo == puntero1) (*frente)->ultimo = puntero2;
		encontrado_y_removido = true;
		}
	}

	free(puntero1);
	return encontrado_y_removido;
}

struct t_nodoCola *nuevo_nodo_cola(){

	struct t_nodoCola *nuevo;
    nuevo = (struct t_nodoCola*) malloc (sizeof(struct t_nodoCola));
    if (nuevo==NULL) printf( "No hay memoria disponible!\n");
    return nuevo;
}

struct t_nodoCola *agregar_pedido_a_cola(struct t_nodoColaGrande **frente_grande, struct t_pedido pedido ) {
	  struct t_nodoCola *nuevo, *fin;
	  int32_t comparacion_string;

	  t_nodoCola *puntero_cola, *puntero_cola_anterior;
	  extern pthread_mutex_t mutexColaGrande;
	  nuevo = nuevo_nodo_cola();
	  (*nuevo).pedido = pedido;
	  (*nuevo).siguiente = NULL;

	  pthread_mutex_lock (&mutexColaGrande);
	  t_nodoColaGrande *puntero1 = *frente_grande;
	  comparacion_string = strcmp(puntero1->planificador_id, pedido.planificador_id);
	  while((puntero1 != NULL) && (comparacion_string != 0)){
		  puntero1 = (*puntero1).siguienteGrande;
		  if(puntero1 != NULL) comparacion_string = strcmp(puntero1->planificador_id, pedido.planificador_id);
	  }
	  pthread_mutex_unlock (&mutexColaGrande);

	  if(puntero1 != NULL){
		  pthread_mutex_lock (&(puntero1->mutex_ppd));
		  if(puntero1->siguiente == NULL) {
			  puntero1->siguiente = nuevo;
			  puntero1->ultimo = nuevo;
			  fin = puntero1->siguiente;
			  sem_post(&puntero1->semaforo_cola);
			  pthread_mutex_unlock (&(puntero1->mutex_ppd));
			  return fin;
		  }
		  else{
			  puntero1->ultimo->siguiente = nuevo;
			  puntero1->ultimo = nuevo;
			  //puntero_cola = puntero1->siguiente;
			  //puntero_cola_anterior = puntero1->siguiente;

			  //while(puntero_cola != NULL){
				//  puntero_cola_anterior = puntero_cola;
				//  puntero_cola = puntero_cola->siguiente;
			  //}
			  fin = nuevo;
			  sem_post(&puntero1->semaforo_cola);
			  pthread_mutex_unlock (&(puntero1->mutex_ppd));
			  return fin;
		  }
	  }
/*
	  if (fin!=NULL) {
		  (*fin).siguiente = nuevo;
	  }
	  fin = nuevo;
	  return fin;

*/
}

void crear_cola_colas(t_nodoColaGrande *frente,t_nodoColaGrande *fin){
	fin = NULL;
	frente = NULL;
}

t_nodoColaGrande *nuevo_nodo_colaGrande(){

	t_nodoColaGrande *nuevo;
    nuevo = (t_nodoColaGrande*) malloc (sizeof(t_nodoColaGrande));
    if (nuevo==NULL) printf( "No hay memoria disponible!\n");
    return nuevo;
}

t_nodoColaGrande *agregar_cola_a_cola(t_nodoColaGrande **frente,t_nodoColaGrande **fin,char planificador_id[25],int32_t socket_id) {
	  struct t_nodoColaGrande *nuevo;
	  int32_t valor;
	  pthread_mutexattr_t mutexattr;

	  nuevo = nuevo_nodo_colaGrande();
	  memset((*nuevo).planificador_id,0,25);
	  memcpy((*nuevo).planificador_id,planificador_id,strlen(planificador_id));
	  (*nuevo).socket_id = socket_id;
	  (*nuevo).siguiente = NULL;
	  (*nuevo).siguienteGrande = NULL;
	  (*nuevo).ppd_muerto = 0;
	  (*nuevo).pedidos_en_proceso = NULL;
	  (*nuevo).ultimo_en_proceso = NULL;
	  //(*nuevo).semaforo = sem_open ("/sem_ppd5", O_CREAT, 0644, 0);
	  //if((*nuevo).semaforo == (sem_t *)-1)
	  //perror("Error creando semáforo inicio_escritura");

	  valor = sem_init(&((*nuevo).semaforo_cola),0,0);
	  //sem_getvalue(&(*nuevo).semaforo_cola,&valor);
	  valor = sem_init(&((*nuevo).semaforo_escritura),0,0);
	  //pthread_mutexattr_setpshared (&mutexattr,PTHREAD_PROCESS_SHARED);
	  //pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP);
	  pthread_mutex_init (&(nuevo->mutex_ppd), NULL);
	  pthread_mutex_init (&(nuevo->mutex_en_proceso), NULL);

	 // valor = sem_wait(&((*nuevo).semaforo));

	  if (*fin!=NULL) {
		  (**fin).siguienteGrande = nuevo;
	  }
	  *fin = nuevo;
	  if(*frente == NULL) *frente = *fin;
	  return *fin;
}

t_nodoColaGrande *suprimir_pedido_especifico_de_cola_grande(t_nodoColaGrande **frente,t_nodoColaGrande **fin, char planificador_id[25]){
	struct t_nodoColaGrande *puntero1, * puntero2;
	int32_t comparacion_string;
	//bool encontrado_y_removido;

	puntero1 = *frente;
	puntero2 = *frente;

	comparacion_string = strcmp(puntero1->planificador_id, planificador_id);
	while(puntero1 != NULL && (comparacion_string != 0)){
		puntero2 = puntero1;
		puntero1 = (*puntero1).siguienteGrande;
		if(puntero1 != NULL) comparacion_string = strcmp(puntero1->planificador_id, planificador_id);
	}

	if(puntero1 == *frente){
		if(*frente == *fin) *fin = NULL;
		*frente = (*puntero1).siguienteGrande;
	}
	else{
		(*puntero2).siguienteGrande = (*puntero1).siguienteGrande;
		if(puntero1 == *fin) *fin = puntero2;
		//encontrado_y_removido = true;
	}
	//free(puntero1);
	return puntero1;
}

void mostrar_cola_de_colas(t_nodoColaGrande *frente){
	struct t_nodoColaGrande *puntero1;
	puntero1 = frente;
	while(puntero1 != NULL){
		 printf("Planificador_id: %s \n",puntero1->planificador_id);
		 puntero1 = (*puntero1).siguienteGrande;
	}
}

char *algoritmoDistribucion(t_nodoColaGrande **frente, int32_t direccionSector,int32_t planificadoresConectados,int32_t cantidadSectores){//char *string_plan
	int32_t i,posicionPlanificador;
	struct t_nodoColaGrande *puntero1 = *frente;

	int32_t a_divisionDisco[planificadoresConectados];

	if (planificadoresConectados == 1){
		return (*frente)->planificador_id;
	}
/*
	while((puntero1 != NULL) && (puntero1->siguiente != NULL) && (puntero1->pedidos_en_proceso != NULL)){
		puntero1 = (*puntero1).siguienteGrande;
	}

	if (puntero1 != NULL){
		return (*puntero1).planificador_id;
	}
*/
	while(puntero1 != NULL){
		if((puntero1->pedidos_en_proceso == NULL) && (puntero1->estado == LISTO)){
			return (*puntero1).planificador_id;
		}
		puntero1 = puntero1->siguienteGrande;
	}

	for ( i=1 ; i<planificadoresConectados ; i++ ){
		a_divisionDisco[i-1] = (cantidadSectores / planificadoresConectados) * i;
	}
	a_divisionDisco[planificadoresConectados-1] = cantidadSectores;

	posicionPlanificador = 1;
	while(direccionSector > a_divisionDisco[posicionPlanificador-1]) {
		posicionPlanificador++;
	}

	puntero1 = *frente;
	i = 1;
	while(i != posicionPlanificador){
		if(puntero1->estado == LISTO){
			i++;
		}
		puntero1 = (*puntero1).siguienteGrande;
	}

/*
	for ( i=1 ; i<=planificadoresConectados ; i++ ){
		printf("Algoritmo de distribucion:");
		printf("planif. %i hasta el: %i \n",i,a_divisionDisco[i]);
	}
	printf("El pedido va al planif: %s \n",puntero1->planificador_id);
*/
/*
	int32_t comparacion_string = strcmp(puntero1->planificador_id,"EA33");
	if(comparacion_string == 0){
		puts("cagamo");
	}
*/

	return puntero1->planificador_id;
}

struct t_nodoCola *agregar_pedido_a_cola_pedidos_en_proceso(struct t_nodoCola **dir_frente, struct t_nodoCola **dir_fin,struct t_pedido pedido ) {
	  struct t_nodoCola *nuevo;
	  //struct t_nodoCola *frente = *dir_frente, *fin = *dir_fin;

	  nuevo = nuevo_nodo_cola();
	  (*nuevo).pedido = pedido;
	  (*nuevo).siguiente = NULL;

	  if (*dir_fin!=NULL) {
		  (*dir_fin)->siguiente = nuevo;
	  }
	  *dir_fin = nuevo;
	  if((*dir_frente) == NULL){
		  *dir_frente = *dir_fin;
	  }
	  return *dir_fin;
}

t_nodoCola *agregar_pedido_a_frente_de_cola(t_nodoColaGrande **frente_grande, t_pedido pedido ) {
	  struct t_nodoCola *nuevo, *fin;
	  int32_t comparacion_string;
	  t_nodoColaGrande *puntero1 = *frente_grande;
	  t_nodoCola *puntero_cola, *puntero_cola_anterior;

	  nuevo = nuevo_nodo_cola();
	  (*nuevo).pedido = pedido;
	  (*nuevo).siguiente = NULL;

	  comparacion_string = strcmp(puntero1->planificador_id, pedido.planificador_id);
	  while((puntero1 != NULL) && (comparacion_string != 0)){
		  puntero1 = (*puntero1).siguienteGrande;
		  if(puntero1 != NULL) comparacion_string = strcmp(puntero1->planificador_id, pedido.planificador_id);
	  }

	  pthread_mutex_lock (&(puntero1->mutex_ppd));
	  if(puntero1->siguiente == NULL) {
		  puntero1->siguiente = nuevo;
		  puntero1->ultimo = nuevo;
		  //fin = puntero1->siguiente;
		  sem_post(&(puntero1->semaforo_cola));
		  pthread_mutex_unlock (&(puntero1->mutex_ppd));
		  return puntero1->siguiente;
	  }
	  else{
		  nuevo->siguiente = puntero1->siguiente;
		  puntero1->siguiente = nuevo;
		  sem_post(&(puntero1->semaforo_cola));
		  pthread_mutex_unlock (&(puntero1->mutex_ppd));
		  return puntero1->siguiente;
	  }
}

char* get_time_string(int mode24)
{
  static char time_str[12] = {0};   /* Stroes the time as a string */
  struct tm *now = NULL;
  int hour = 0;
  time_t time_value = 0;

  time_value = time(NULL);          /* Get time value              */
  now = localtime(&time_value);     /* Get time and date structure */
  hour = now->tm_hour;              /* Save the hour value         */
  if(!mode24 && hour>12)            /* Adjust if 12 hour format    */
    hour -= 12;

  printf("%d:",hour);
  printf("%d:",now->tm_min);
  printf("%d",now->tm_sec);


  if(!mode24)
    if(now->tm_hour>24){
       printf("PM\n");
    }else{
       printf("AM\n");
     }
  return time_str;
}

void insertarEnArray(int32_t array[CANT_CLIENTES_PPD_MAX],int32_t socket_id){
	int32_t i = 0;

	while(array[i] != -1){
		i++;
	}
	array[i] = socket_id;
}

void inicializoArray(int32_t array[CANT_CLIENTES_PPD_MAX]){
	int32_t i;
	for(i=0 ; i < CANT_CLIENTES_PPD_MAX; i++){
		array[i] = -1;
	}
}
void eliminoDeArray(int32_t array[CANT_CLIENTES_PPD_MAX],int32_t socket_id){
	int32_t i = 0 ,o = 0;
	while(array[i] != socket_id){
		i++;
	}
	for (o = i; i == CANT_CLIENTES_PPD_MAX; o++){
		array[o] = array[o+1];
	}
}

bool eliminar_pedido_de_cola_pedidos_en_proceso(t_nodoCola **frente,t_nodoCola **fin,t_pedido pedido){
	t_nodoCola *puntero1 = *frente, *puntero2 = *frente;
	int comparacion_string;
	bool encontrado_y_removido;

	comparacion_string = strcmp((*puntero1).pedido.planificador_id, pedido.planificador_id);
	//comparacion_string2 = strcmp((*puntero1).pedido.lectura_o_escritura, pedido.lectura_o_escritura);
	while((puntero1 != NULL) && (((*puntero1).pedido.direccionSector != pedido.direccionSector) || ((*puntero1).pedido.conexion_ppd_id != pedido.conexion_ppd_id) || ((*puntero1).pedido.conexion_pfs_id != pedido.conexion_pfs_id) || ((*puntero1).pedido.lectura_o_escritura != pedido.lectura_o_escritura) || (comparacion_string != 0))){
		puntero2 = puntero1;
		puntero1 = puntero1->siguiente;
		if(puntero1 != NULL) {
			comparacion_string = strcmp((*puntero1).pedido.planificador_id, pedido.planificador_id);
			//comparacion_string2 = strcmp((*puntero1).pedido.lectura_o_escritura, pedido.lectura_o_escritura);
		}
	}

	if(puntero1 == *frente){
		*frente = (*puntero1).siguiente;
		encontrado_y_removido = true;
		if(puntero1 == *fin) *fin = NULL;
	}
	else{
		if(puntero1 == NULL){
			encontrado_y_removido = false;
			return encontrado_y_removido;
		}
		else{
		(*puntero2).siguiente = (*puntero1).siguiente;
		encontrado_y_removido = true;
		if(puntero1 == *fin) *fin = puntero2;
		}
	}
	free(puntero1);
	return encontrado_y_removido;
}

bool eliminar_pedido_de_cola_en_proceso_de_sector_n(t_nodoCola **frente,t_nodoCola **fin,int32_t sector){
	t_nodoCola *puntero1 = *frente, *puntero2 = *frente;
	int comparacion_string;
	bool encontrado_y_removido;

	while((puntero1 != NULL) && (puntero1->pedido.direccionSector != sector)){
		puntero2 = puntero1;
		puntero1 = (*puntero1).siguiente;
	}

	if(puntero1 == NULL){
		encontrado_y_removido = false;
		return encontrado_y_removido;
	}

	if(puntero1 == *frente){
		*frente = (*puntero1).siguiente;
		encontrado_y_removido = true;
		if(puntero1 == *fin) *fin = NULL;
	}
	else{
		(*puntero2).siguiente = (*puntero1).siguiente;
		encontrado_y_removido = true;
		if(puntero1 == *fin) *fin = puntero2;
	}
	free(puntero1);
	return encontrado_y_removido;
}

void crearLog(){
		logger=log_create("RAID", "./raid.log",WARNING | DEBUG | ERROR | INFO, M_CONSOLE_DISABLE);
}

void cargaConfiguracionInicial(){

	static struct Configuration *configuration;
	//config configuracionDevuelve;

	//configuration = new(Configuration, "/home/utn_so/Desarrollo/Workspace/PPD/Config.ini", "=");
	configuration = new(Configuration, "Config.ini", "=");
	strcpy(configuracion.IPRAID,ConfigurationClass.getString(configuration, "IPRAID"));
	configuracion.ConsolaActiva=ConfigurationClass.getInt(configuration, "ConsolaActiva");
	configuracion.PuertoEscuchaPfs=ConfigurationClass.getInt(configuration, "PuertoEscuchaPfs");
	configuracion.PuertoEscuchaPpd=ConfigurationClass.getInt(configuration, "PuertoEscuchaPpd");
	configuracion.cantPFSMax=ConfigurationClass.getInt(configuration, "CANT_CLIENTES_PFS_MAX");
	configuracion.logActivado=ConfigurationClass.getInt(configuration, "logActivo");

	Configuration_destroyer(configuration);

	//return configuracion;
}

void insertarEnListaClientes(int32_t cliente_pfs){
	NodoPFS *aux;

	// creo el nodo a insertar
	NodoPFS *nuevo=(NodoPFS*)malloc(sizeof(NodoPFS));

	nuevo->sig=NULL;
	nuevo->cliente_pfs=cliente_pfs;

	if( listaPFS == NULL )
	{
		listaPFS = nuevo;
	}
	else
	{
		aux = listaPFS;
		while( aux->sig != NULL )
		{
			aux = aux->sig;
		}

		aux->sig = nuevo;
	}

	cantidadClientesPFS++;
}

void borrarDeListaClientes(int32_t cliente_pfs){

	NodoPFS *aux, *anterior;

	anterior = NULL;

	for (aux = listaPFS;
			aux != NULL;
			anterior = aux, aux = aux->sig) {


		if (((aux->cliente_pfs == cliente_pfs))) {  /* Encontrado */
			if (anterior == NULL) {

				listaPFS = aux->sig;
			} else {

				anterior->sig = aux->sig;
			}

			free(aux);

			// cantidadTotalPedidos--;

			return;
		}
	}
	cantidadClientesPFS--;

}
